#include <stdio.h>
#include <string.h>
#include "mmu.h"
#include "log.h"
void CCP15::reset()
{
	memset(regs,0,sizeof(regs));
	// hard code register 0
	reg0.w[0]=(ArmImpentor_Arm<<24)|
		(1<<23) |
		(6<<16)|
		(ARMarchitecturev5T<<16)|
		(0x926<<4)|//primary part number,The top four bits of this number are not allowed to be 0x0 or 0x7
		0;
	reg0.w[1]=0;
	reg0.w[2]=0;
	reg0.w[3]=0;
	reg1.s.ControlRegister.M=0;
	reg1.s.ControlRegister.C=0;
}
void  CMMU::exec_mcr(__u32 cmd,__u32 Rd)
{
	union
	{
		ARM_INSN_MCR mcr;
		__u32 w;
	};

	w=cmd;

	//log("mcr:%x %x (%x) :%d(%x)\n",mcr.CRn,mcr.CRm,mcr.opcode2,mcr.Rd,Rd);
	switch(mcr.CRn)
	{
	case 0:
			//Writing to CP15 register 0 is UNPREDICTABLE.

		break;
	case 1:
		if(mcr.opcode2<sizeof(cp15.reg1)/sizeof(__u32))
			cp15.reg1.w[mcr.opcode2]=Rd;
		break;
	case 2:
		if(mcr.opcode2<sizeof(cp15.reg2)/sizeof(__u32))
		cp15.reg2.w[mcr.opcode2]=Rd;
		break;
	case 5:
		if(mcr.opcode2<sizeof(cp15.reg5)/sizeof(__u32))
		cp15.reg5.w[mcr.opcode2]=Rd;
		break;
	case 6:
		if(mcr.opcode2<sizeof(cp15.reg6)/sizeof(__u32))
		cp15.reg6.w[mcr.opcode2]=Rd;
		break;
	case 7:
	case 8:

		break;
	case 13:
		if(mcr.opcode2<sizeof(cp15.reg13)/sizeof(__u32))
		cp15.reg13.w[mcr.opcode2]=Rd;
		break;
	default:
		cp15.regs[mcr.CRn]=Rd;
	}
}
__u32 CMMU::exec_mrc(__u32 cmd)
{
	__u32 Rd=0;
	union
	{
		ARM_INSN_MRC mrc;
		__u32 w;
	};

	w=cmd;
	//log("mrc:%x %x (%x) =%x\n",mrc.CRn,mrc.CRm,mrc.opcode2,mrc.Rd);
	switch(mrc.CRn)
	{
	case 0:
		//the CRm field must be specified as c0 
		//if it is not, the instruction is UNPREDICTABLE
		if(mrc.CRm==0)
		{
			if(mrc.opcode2<sizeof(cp15.reg0)/sizeof(__u32))
				Rd=cp15.reg0.w[mrc.opcode2];
			else
				Rd=cp15.reg0.w[0];
		}

		break;
	case 1:
		if(mrc.opcode2<sizeof(cp15.reg1)/sizeof(__u32))
		Rd=cp15.reg1.w[mrc.opcode2];
		break;
	case 2:
		if(mrc.opcode2<sizeof(cp15.reg2)/sizeof(__u32))
		Rd=cp15.reg2.w[mrc.opcode2];
		break;
	case 5:
		if(mrc.opcode2<sizeof(cp15.reg5)/sizeof(__u32))
		Rd=cp15.reg5.w[mrc.opcode2];
		break;
	case 6:
		if(mrc.opcode2<sizeof(cp15.reg6)/sizeof(__u32))
		Rd=cp15.reg6.w[mrc.opcode2];
		break;
	case 7:
		//Register 7: cache control and similar functions
		Rd=1<<30;

		break;
	case 8:
		//Register 8: TLB functions
		Rd=0;
		break;
	case 10:
		Rd=0;
		break;
	case 13:
		if(mrc.opcode2<sizeof(cp15.reg13)/sizeof(__u32))
		Rd=cp15.reg13.w[mrc.opcode2];
		break;
	default:
		Rd=cp15.regs[mrc.CRn];
	}

	return Rd;
}


void  CCP15::setFSR(__u8 status,bool code)
{
	if(code) 
	{
		reg5.s.InsnFSR.Status=status&0xf;
		reg5.s.InsnFSR.FS4=(status>>4);
	}
	else
	{
		reg5.s.DataFSR.Status=status&0xf;
		reg5.s.DataFSR.FS4=(status>>4);
	}
}
void  CCP15::setFAR(__u32 address,bool code)
{
	if(code) 
	{
		reg6.s.IFAR=address;
	}
	else
	{
		reg6.s.DFAR=address;
	}
}